package crypt;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

/**
 * 
 * @author Julian Beisert
 * @version 1.0
 */
public class CryptAES {

	private SecretKey _key;
	private static CryptAES _instance = null;

	private CryptAES() {
	}

	/**
	 * generate symmetric AES Keyo
	 */
	private void generateKey() {

		KeyGenerator keygen = null;
		try {
			keygen = KeyGenerator.getInstance("AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		keygen.init(128);
		this._key = keygen.generateKey();
	}

	/**
	 * 
	 * @param data
	 *            data to encrypt
	 * 
	 * @return encrypted data
	 */
	public byte[] encrypt(byte[] data) {
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		try {
			cipher.init(Cipher.ENCRYPT_MODE, this._key);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		byte[] encrypt = null;
		try {
			encrypt = cipher.doFinal(data);
		} catch (IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return encrypt;
	}

	/**
	 * 
	 * @param data
	 *            data to encrypt
	 * 
	 * @param key
	 *            symmetric key for encryption
	 * 
	 * @return decrypted data
	 */
	public byte[] decrypt(byte[] data, SecretKey key) {
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		try {
			cipher.init(Cipher.DECRYPT_MODE, key);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		byte[] decrypt = null;
		try {
			decrypt = cipher.doFinal(data);
		} catch (IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return decrypt;
	}

	/**
	 * 
	 * @return get symmetric Key for AES Encryption
	 */
	public SecretKey getSymmetricKey() {
		return this._key;
	}

	public void setSymmetricKey(SecretKey key) {
		this._key = key;
	}

	/**
	 * 
	 * @return get encryption Cipher with actual key
	 */
	public Cipher getEncryptionCipher() {
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		try {
			cipher.init(Cipher.ENCRYPT_MODE, this._key);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		return cipher;
	}

	/**
	 * 
	 * @return get decryption Cipher with actual key
	 */
	public Cipher getDecryptionCipher() {
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("AES");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		try {
			cipher.init(Cipher.DECRYPT_MODE, this._key);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		return cipher;
	}

	/**
	 * 
	 * @return Singelton CryptAES Object
	 */
	public static CryptAES getInstance() {
		if (_instance == null) {
			_instance = new CryptAES();
			_instance.generateKey();
		}
		return _instance;

	}

}
